package com.huaguoguo.spring.context;

import com.huaguoguo.spring.annotation.Autowired;
import com.huaguoguo.spring.annotation.Component;
import com.huaguoguo.spring.annotation.Configuration;
import com.huaguoguo.spring.annotation.Service;
import com.huaguoguo.spring.context.config.BeanDefinition;
import com.huaguoguo.spring.context.config.ConfigurBeanDefinition;
import com.huaguoguo.spring.execption.BeanRegisterExecption;
import com.huaguoguo.spring.execption.BeansException;
import com.huaguoguo.spring.util.StringUtils;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.*;

/**
 * description: bean信息扫描并加入到容器
 * author:huaguoguo
 * Date: 2018/12/8
 * Time: 17:36
 */
@Slf4j
public class BeanDefinitionScanner {

    private String packageName;

    /**
     * 需要延迟加载的bean
     */
    private Map<String, DelayLoadBean> delayLoadBeanMap = new HashMap<>(64);

    private RegisterBeanDefinition register;

    private Map<String, Object> beanMap;

    public BeanDefinitionScanner(String basePackage) {
        this.packageName = basePackage;
        List<Integer> integers = Arrays.asList(1, 2, 3);

    }

    public BeanDefinitionScanner(RegisterBeanDefinition register) {
        this.register = register;
    }

    /**
     * 扫描bean，加入到map中
     *
     * @return
     */
    public Map<String, Object> sacnner() throws Exception {
        beanMap = new HashMap<>(64);
        scannerSystemBean();
        scannerCustomerBean();
        return beanMap;
    }

    /**
     * 扫描系统中需要用到的bean
     */
    private void scannerSystemBean() {
    }

    /**
     * 扫描自定义的bean
     */
    private void scannerCustomerBean() throws Exception {

        //初始化bean，new出来
        initCustomerBean();
        //检查对象的属性是否有@Autowired
//        autowiredField(beanName, newInstance);

    }

    private void autowiredField(String beanName, Object newInstance) throws Exception {
        Class<?> aClass = newInstance.getClass();
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            Autowired autowired = field.getAnnotation(Autowired.class);
            if (autowired != null) {
                String fieldName = field.getName();
                Object fieldValue = beanMap.get(fieldName);
                if (fieldValue == null && autowired.required()) {
                    BeanDefinition beanDefinition = register.beanDefinitionMap.get(fieldName);
                    if (beanDefinition == null) {
                        throw new BeansException(String.format("没有找到合适的bean可以注入到%s的属性%s中！",
                                beanName, field.getName()));
                    }else {
                        fieldValue = createBean(beanDefinition);
                        autowiredField(fieldName,fieldValue);
                    }

                }
                field.setAccessible(true);
                field.set(newInstance, fieldValue);
            }

        }


    }

    private void initCustomerBean() {
//        for (Class<?> aClass : classList) {
//            createBean(aClass);
//        }
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : register.beanDefinitionMap.entrySet()) {
            BeanDefinition beanDefinition = beanDefinitionEntry.getValue();
            Object bean = createBean(beanDefinition);
            try {
                autowiredField(beanDefinitionEntry.getKey(),bean);
            } catch (Exception e) {
                throw new BeanRegisterExecption(String.format("创建bean：%s失败", beanDefinition.getBeanName()));
            }
        }


    }


    private Object createBean(BeanDefinition beanDefinition) throws BeanRegisterExecption {
        String beanName = beanDefinition.getBeanName();
        //已经创建了就直接跳出
        if (beanMap.containsKey(beanName)) {
            return beanMap.get(beanName);
        }
        Object newInstance = null;
        try {
            if (beanDefinition instanceof ConfigurBeanDefinition) {
                newInstance = createConfiguarBean(((ConfigurBeanDefinition) beanDefinition));
            } else {
                newInstance = beanDefinition.getBeanType().newInstance();
            }

            beanMap.put(beanName, newInstance);
            return newInstance;

        } catch (Exception e) {
            throw new BeanRegisterExecption(String.format("创建bean：%s失败", beanName));
        }
    }

    private Object createConfiguarBean(ConfigurBeanDefinition beanDefinition) throws Exception {
        // 没有配置类先创建配置类
        String beanName = beanDefinition.getParentBeanName();
        Object parentBean = null;
        if (!beanMap.containsKey(beanName)) {
            parentBean = createBean(register.beanDefinitionMap.get(beanName));
            autowiredField(beanName,parentBean);
        } else {
            parentBean = beanMap.get(beanName);
        }
        Object configBean = beanDefinition.getMethod().invoke(parentBean, null);
        return configBean;
    }

    private void createBean(Class<?> aClass) {
        try {
            Annotation[] annotations = aClass.getAnnotations();
            for (Annotation annotation : annotations) {
                String annotationName = annotation.annotationType().getSimpleName();
                String beanName = null;
                switch (annotationName) {
                    case "Configuration":
                        beanName = ((Configuration) annotation).value();
//                        new ConfigurationBeanLoad().beanload(beanMap,aClass,delayLoadBeanMap);
                        break;
                    case "Service":
                        beanName = ((Service) annotation).value();
                        break;
                    case "Component":
                        beanName = ((Component) annotation).value();
                        break;
                    default:
                        continue;
                }
                if (StringUtils.isEmpty(beanName)) {
                    beanName = StringUtils.toLowerCaseFirstOne(aClass.getSimpleName());
                }
                if (beanMap.containsKey(beanName)) {
                    throw new BeanRegisterExecption(String.format("存在同名bean：%s,请检查你的代码！", beanName));
                }
                Object beanInstance = aClass.newInstance();
                beanMap.put(beanName, beanInstance);
                log.info("实例化对象 {}：{}", aClass.getTypeName(), beanName);
                new AutowiredHandler().autowiredField(beanMap, beanInstance);
                return;
            }
        } catch (Exception e) {
            log.error("创建对象{}失败", aClass.getSimpleName(), e);
        }

    }
}
